#include <stdio.h>
#include <stdlib.h>
#include <sndfile.h>
#include "util.h"
#include "audiosource.h"
#include "audioencoder_sndfile.h"

struct AUDIOENCODER_SNDFILE {
	AUDIOENCODER encoder;

	SNDFILE *sndfile;
	SF_INFO sf_info;
	AUDIOSOURCE *source;
	long framepos;
};

/**
 * End of file?
 */
static int eof(AUDIOENCODER *e) {
	AUDIOENCODER_SNDFILE *encoder=(AUDIOENCODER_SNDFILE *)e;

	if (encoder->framepos>=audiosource_get_numsamples(encoder->source))
		return 1;

	else
		return 0;
}

/**
 * Encode.
 */ 
static int encode(AUDIOENCODER *e, int length) {
	TRACE("** sndfile encoder: encoding..\n");
	AUDIOENCODER_SNDFILE *encoder=(AUDIOENCODER_SNDFILE *)e;

	if (audioencoder_eof(e))
		return 0;

	int numframes=length*44100/1000;

	if (encoder->framepos+numframes>audiosource_get_numsamples(encoder->source))
		numframes=audiosource_get_numsamples(encoder->source)-encoder->framepos;

	float samples[2*numframes*sizeof(float)];

	TRACE("geting samples: %d\n",numframes);
	int res=audiosource_get_samples(encoder->source,samples,numframes);
	TRACE("get samples res: %d\n",res);
	if (!res)
		memset_float(samples,0,numframes*2);

	int i;
	for (i=0; i<2*numframes; i++) {
		if (samples[i]>1.0)
			samples[i]=1.0;

		if (samples[i]<-1.0)
			samples[i]=-1.0;
	}

	sf_count_t written=sf_writef_float(encoder->sndfile,samples,numframes);

	if (written!=numframes)
		fail("unable to write to wav file.");

	encoder->framepos+=numframes;
	return numframes;
}

/**
 * Destructor.
 */
static void dispose(AUDIOENCODER *e) {
	TRACE("**** disposing wav..\n");
	AUDIOENCODER_SNDFILE *encoder=(AUDIOENCODER_SNDFILE *)e;

	sf_write_sync(encoder->sndfile);
	sf_close(encoder->sndfile);

	free(encoder);
}

/**
 * Constrcutor.
 */
AUDIOENCODER_SNDFILE *audioencoder_sndfile_create(char *target, AUDIOSOURCE *source, int position) {
	AUDIOENCODER_SNDFILE *encoder;

	encoder=nicemalloc(sizeof(AUDIOENCODER_SNDFILE));

	encoder->encoder.encode_func=encode;
	encoder->encoder.eof_func=eof;
	encoder->encoder.dispose_func=dispose;
	encoder->framepos=(long long)position*44100/1000;

	encoder->sf_info.samplerate=44100;
	encoder->sf_info.channels=2;
	encoder->sf_info.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;

	TRACE("sndfile target: %s\n",target);
	if (target)
		encoder->sndfile=sf_open(target,SFM_WRITE,&encoder->sf_info);

	else
		fail("Cannot write wav to stdout currently.");

	if (!encoder->sndfile)
		fail("Unable to open outfile.");

	encoder->source=source;
	audiosource_set_streampos(encoder->source,encoder->framepos);

	return encoder;
}
